package com.nageoffer.jobtrain.projects.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.nageoffer.jobtrain.common.web.exception.ClientException;
import com.nageoffer.jobtrain.projects.common.biz.user.UserContext;
import com.nageoffer.jobtrain.projects.common.constant.RedisCacheConstant;
import com.nageoffer.jobtrain.projects.common.enums.UserStatusEnums;
import com.nageoffer.jobtrain.projects.config.MinioConfig;
import com.nageoffer.jobtrain.projects.dao.entity.UserDO;
import com.nageoffer.jobtrain.projects.dao.mapper.UserMapper;
import com.nageoffer.jobtrain.projects.dto.req.UserBlockingReqDTO;
import com.nageoffer.jobtrain.projects.dto.req.UserEditUserInfoReqDTO;
import com.nageoffer.jobtrain.projects.dto.req.UserLiftingReqDTO;
import com.nageoffer.jobtrain.projects.dto.req.UserPageReqDTO;
import com.nageoffer.jobtrain.projects.dto.resp.UserDetailRespDTO;
import com.nageoffer.jobtrain.projects.dto.resp.UserInfoRespDTO;
import com.nageoffer.jobtrain.projects.dto.resp.UserPageRespDTO;
import com.nageoffer.jobtrain.projects.service.UserService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * author：唐晨
 */
@Service
@RequiredArgsConstructor
public class UserServiceImpl extends ServiceImpl<UserMapper, UserDO> implements UserService {
    private final UserMapper userMapper;
    private final StringRedisTemplate stringRedisTemplate;
    private final MinioConfig minioConfig;

    @Override
    public IPage<UserPageRespDTO> pageUserList(UserPageReqDTO requestParam) {
        Page<UserPageRespDTO> page = new Page<>(requestParam.getCurrent(), requestParam.getSize());
        List<UserPageRespDTO> result = userMapper.pageUserList(requestParam.getPhoneNumber(), requestParam.getNickName(), page);
        page.setRecords(result);
        return page;
    }

    @Override
    public void blockingUserStatus(UserBlockingReqDTO requestParam) {
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getPhoneNumber, requestParam.getPhoneNumber())
                .eq(UserDO::getDelFlag, 0);
        UserDO userDO = userMapper.selectOne(queryWrapper);
        if (userDO == null) {
            throw new ClientException("无该用户的基本信息");
        }
        if (Objects.equals(userDO.getStatus(), UserStatusEnums.BLOCKING.getType())) {
            throw new ClientException("该用户已经是拉黑状态");
        }
        LambdaUpdateWrapper<UserDO> updateWrapper = Wrappers.lambdaUpdate(UserDO.class)
                .eq(UserDO::getPhoneNumber, requestParam.getPhoneNumber())
                .set(UserDO::getStatus, UserStatusEnums.BLOCKING.getType())
                .eq(UserDO::getDelFlag, 0);
        userMapper.update(updateWrapper);
    }

    @Override
    public void liftingUserStatus(UserLiftingReqDTO requestParam) {
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getPhoneNumber, requestParam.getPhoneNumber())
                .eq(UserDO::getDelFlag, 0);
        UserDO userDO = userMapper.selectOne(queryWrapper);
        if (userDO == null) {
            throw new ClientException("无该用户的基本信息");
        }
        if (Objects.equals(userDO.getStatus(), UserStatusEnums.NORMAL.getType())) {
            throw new ClientException("该用户已经是正常状态");
        }
        LambdaUpdateWrapper<UserDO> updateWrapper = Wrappers.lambdaUpdate(UserDO.class)
                .eq(UserDO::getPhoneNumber, requestParam.getPhoneNumber())
                .set(UserDO::getStatus, UserStatusEnums.NORMAL.getType())
                .eq(UserDO::getDelFlag, 0);
        userMapper.update(updateWrapper);
    }

    @Override
    public Boolean logoutUser() {
        String phoneNumber = UserContext.getUsername();
        if (StrUtil.isEmpty(phoneNumber)) {
            throw new ClientException("未获取到用户登录信息");
        }
        String userTokenCacheKey = RedisCacheConstant.USER_LOGIN_KEY + phoneNumber;
        return Optional.ofNullable(stringRedisTemplate.opsForValue().get(userTokenCacheKey))
                .map(value -> stringRedisTemplate.delete(userTokenCacheKey))
                .orElse(false);
    }

    @Override
    public UserDetailRespDTO detailUser() {
        // 从用户上下文中获取到过滤器中解析的用户信息
        String phoneNumber = UserContext.getUsername();
        if (StrUtil.isEmpty(phoneNumber)) {
            throw new ClientException("未获取到用户登录详情信息");
        }
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getPhoneNumber, Long.valueOf(phoneNumber))
                .eq(UserDO::getDelFlag, 0);
        UserDO userDO = userMapper.selectOne(queryWrapper);
        if (userDO == null) {
            throw new ClientException("暂无该用户信息");
        }
        return BeanUtil.toBean(userDO, UserDetailRespDTO.class);
    }

    @Override
    public UserInfoRespDTO getUserInfo() {
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getPhoneNumber, UserContext.getUsername())
                .eq(UserDO::getDelFlag, 0);
        UserDO userDO = userMapper.selectOne(queryWrapper);
        return BeanUtil.toBean(userDO, UserInfoRespDTO.class);
    }

    @Override
    public void editUserInfo(UserEditUserInfoReqDTO requestParam) {
        LambdaQueryWrapper<UserDO> queryWrapper = Wrappers.lambdaQuery(UserDO.class)
                .eq(UserDO::getPhoneNumber, UserContext.getUsername())
                .eq(UserDO::getDelFlag, 0);
        UserDO userDO = userMapper.selectOne(queryWrapper);
        if (userDO == null) {
            throw new ClientException("该用户基本信息详情不存在");
        }
        userDO = UserDO.builder()
                .nickName(requestParam.getNickName())
                .email(requestParam.getEmail())
                .sex(requestParam.getSex())
                .school(requestParam.getSchool())
                .wechat(requestParam.getWechat())
                .professional(requestParam.getProfessional())
                .introduce(requestParam.getIntroduce())
                .build();
        LambdaUpdateWrapper<UserDO> updateWrapper = Wrappers.lambdaUpdate(UserDO.class)
                .eq(UserDO::getPhoneNumber, UserContext.getUsername())
                .eq(UserDO::getDelFlag, 0);
        userMapper.update(userDO, updateWrapper);
    }

    @Override
    public void upLoadUserHeadShot(MultipartFile multipartFile) {
        try {
            // 校验文件是否为空
            if (multipartFile.isEmpty()) {
                throw new ClientException("上传文件不能为空");
            }
            // 获取文件名和文件类型
            String originalFilename = multipartFile.getOriginalFilename();
            if (originalFilename == null) {
                throw new ClientException("文件名不能为空");
            }
            // 获取文件扩展名
            String fileExtension = getFileExtension(originalFilename);
            if (!isSupportedImageFormat(fileExtension)) {
                throw new ClientException("仅支持 jpg 和 png 格式的图片");
            }
            // 构造新的文件名，避免文件名冲突 -使用用户手机号
            String newFileName = UserContext.getUsername() + "." + fileExtension;
            // 获取文件流和内容类型
            InputStream inputStream = multipartFile.getInputStream();
            String contentType = multipartFile.getContentType();
            String fileUrl = minioConfig.uploadFile(newFileName, inputStream, contentType);
            LambdaUpdateWrapper<UserDO> updateWrapper = Wrappers.lambdaUpdate(UserDO.class)
                    .eq(UserDO::getPhoneNumber, UserContext.getUsername())
                    .set(UserDO::getHeadShot, fileUrl)
                    .eq(UserDO::getDelFlag, 0);
            userMapper.update(updateWrapper);
        } catch (Throwable ex) {
            // 捕获异常并抛出自定义异常
            throw new ClientException("头像上传失败: " + ex.getMessage());
        }
    }

    /**
     * 获取文件扩展名（小写）
     *
     * @param fileName 文件名
     * @return 文件扩展名
     */
    private String getFileExtension(String fileName) {
        int lastIndexOfDot = fileName.lastIndexOf(".");
        if (lastIndexOfDot == -1) {
            throw new ClientException("文件没有扩展名");
        }
        return fileName.substring(lastIndexOfDot + 1).toLowerCase();
    }

    /**
     * 校验是否为支持的图片格式
     *
     * @param fileExtension 文件扩展名
     * @return 是否支持
     */
    private boolean isSupportedImageFormat(String fileExtension) {
        return "jpg".equals(fileExtension) || "png".equals(fileExtension);
    }
}
